package ar.edu.utn.frba.gdaia.src.action;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;

import ar.edu.utn.frba.gdaia.src.domain.Canal;
import ar.edu.utn.frba.gdaia.src.domain.Concepto;
import ar.edu.utn.frba.gdaia.src.domain.ConceptoElemental;
import ar.edu.utn.frba.gdaia.src.domain.Regla;
import ar.edu.utn.frba.gdaia.src.domain.ReglaElemental;
import ar.edu.utn.frba.gdaia.src.domain.Situacion;
import ar.edu.utn.frba.gdaia.src.main.Cerebro;
import ar.edu.utn.frba.gdaia.src.util.ListBuilder;

/**
 * @author Fernando: clase creada para combinar conceptos. 21/08/06
 * 
 * @author Javier: Implementacion de la clase. 19/03/07
 */
public class ConceptoInstruccionConceptosCantidadCommand extends Command {

	public void execute(Map parameters) {
		
		Cerebro cerebro = (Cerebro) parameters.get(Command.CEREBRO);
		Canal canalI=Canal.INT_CONCEPTO_INSTRUCCION_CONCEPTO_CANTIDAD;
		ConceptoElemental conceptoComodin=new ConceptoElemental(10001, Concepto.CONC_INSTR_CANTIDAD,canalI);
		Set listaCorta = (HashSet) parameters.get(Command.LISTA_CORTA);
		List<Concepto> sitFin,sitIni;
		Concepto concAux=null;
		Concepto conceptoCant=null;
		ArrayList<Regla> nuevasReglas=new ArrayList<Regla>();
		ArrayList<ReglaAEvaluar> testReglas = new ArrayList<ReglaAEvaluar>();
		ArrayList<ReglaAEvaluar> reglasAUnificar = new ArrayList<ReglaAEvaluar>();
		boolean flag=false;
		// si no hay lista corta salimos
		if (listaCorta == null) return;
		
		System.out.println("Mi lista Corta: "+listaCorta);
		for(Regla reglaListaCorta:(HashSet<Regla>)listaCorta){
			concAux=null;
			flag=false;
			for(Concepto consSitFin: sitFin=(List<Concepto>)reglaListaCorta.getSituacionFinal().getEstado()){
				if(concAux==null){
					concAux=consSitFin;
					flag=false;
					continue;
				}else if(concAux.equals(consSitFin)){
					flag=true;
					continue;
				}else{
					flag=false;
					break;
				}
			}
			if (flag){
				sitIni=(List<Concepto>)reglaListaCorta.getSituacionInicial().getEstado();
				if(sitIni.contains(concAux)){
					//Genero la nueva regla posible de testear					
					testReglas.add(new ReglaAEvaluar(reglaListaCorta,concAux,sitFin.size()));  //Lista de Reglas a Evaluar
				}
			}							
		}
		//Ahora con la lista de reglas que tienen todos los Conceptos de la Sit Final iguales, 
		//busco los que tengan conceptos repetidos en la Sit inicial y que NO sea el concepto repetido
		ReglaAEvaluar reglaEval, reglaInspeccionada;
		for(int i=0;i<testReglas.size();i++){
			reglaEval=testReglas.get(i);
			for(Concepto conSitIni:(List <Concepto>)reglaEval.getSituacionInicial().getEstado()){
				if(conSitIni.equals(reglaEval.getConcRepetido())){
					continue;
				}
				reglasAUnificar.clear(); //Limpio la lista de Reglas que cumplen todo
				for(int j=i+1;j<testReglas.size();j++){
					reglaInspeccionada=testReglas.get(j);
					//Si el concepto esta en las 2 Sit Iniciales de las dos reglas y la cantidad repetida es la misma entonces son elegibles las reglas
					if ((reglaInspeccionada.getSituacionInicial().getEstado().contains(conSitIni))&&(reglaInspeccionada.getCantRep()==reglaEval.getCantRep())){					
						if(reglasAUnificar.isEmpty()){
							reglaEval.setConsCant(conSitIni);
							reglasAUnificar.add(reglaEval);							
						}	
						reglaInspeccionada.setConsCant(conSitIni);
						reglasAUnificar.add(reglaInspeccionada);					
					}		
				}
				if (reglasAUnificar.size()>2){
					//Make Regla
					/*TODO: buscar en la situaciones iniciales de la lista de reglasAUnificar los conceptos que se repiten y despues 
					  usarlos para la regla la situacion inicial - Armar una funcion que dadas 2 situaciones saque la interseccion de ambos.
					*/
					
					List sitIniCommon=reglasAUnificar.get(0).getSituacionInicial().getEstado();
					for (int k=1;k<reglasAUnificar.size();k++){
						sitIniCommon=ListUtils.intersection(sitIniCommon, reglasAUnificar.get(k).getSituacionInicial().getEstado());
						}
					
					Concepto concCant=reglasAUnificar.get(0).getConcCant();
					int cantRep=reglasAUnificar.get(0).getCantRep();
					
					Situacion sitIniNew= new Situacion(new ListBuilder(sitIniCommon).add(conceptoComodin).get(),canalI);
					Situacion sitFinNew= new Situacion(new ListBuilder().add(conceptoComodin).get(),canalI);
						for(int k=1;k<cantRep;k++){
							sitFinNew.getEstado().add(conceptoComodin);
						}										
					nuevasReglas.add(
							new ReglaElemental(
									cerebro.getNextConceptNumber(),null,new Date(),sitIniNew,null,
									sitFinNew,null,canalI));
				}
			}
		}
//		System.out.println("Reglas Generadas: "+nuevasReglas);
		//TODO: Deberia estar afuera de esta rutina, devolver la lista de nuevas reglas como un parametro
		cerebro.grabarReglas(nuevasReglas);		
	}
}

class ReglaAEvaluar extends Regla{
	private Concepto concRepetido;
	private Concepto concCant;
	
	int cantRep;
	
	ReglaAEvaluar(Regla reglaOrig,Concepto concRepetido,int cantRep){
		super(reglaOrig.getNroIdent(),reglaOrig.getUso(),reglaOrig.getUltimoUso(),reglaOrig.getSituacionInicial(),reglaOrig.getSituacionIntermedia(),reglaOrig.getSituacionFinal(),reglaOrig.getCanalIngreso());
		this.concRepetido=concRepetido;
		this.cantRep=cantRep;
	}

	public int getCantRep() {
		return cantRep;
	}

	public Concepto getConcRepetido() {
		return concRepetido;
	}

	public Concepto getConcCant() {
		return concCant;
	}

	public void setConsCant(Concepto concCant) {
		this.concCant = concCant;
	}	
}